package org.javahispano.javacup.tacticas_aceptadas.Moyatzo.MoyatzoBraves;

import org.javahispano.javacup.modelo.*;

public class Utilidades {

	// Retorna la distancia al cuadrado. Es un m�todo de optimizaci�n, nos
	//  ahorramos las costosas ra�ces cuadradas.
	static public double DistanciaAlCuadrado(Posicion a_p1, Posicion a_p2)
	{
		double d1 = Math.pow( ( a_p1.getX( ) - a_p2.getX( ) ), 2 );
		double d2 = Math.pow( ( a_p1.getY( ) - a_p2.getY( ) ), 2 );
		return ( d1 + d2 );
	}
	
	// Obtiene el �ndice del jugador que es portero del equipo rival.
	static public int ObtenerIndicePorteroRival( SituacionPartido a_sit_part )
	{	
		// Obtenemos los detalles de cada jugador rival.
		JugadorDetalle[] det_rivales = a_sit_part.detalleJugadoresRivales();
		
		int i_indice_actual = 0,
			i_num_rivales = det_rivales.length;
		
		// Iteramos sobre cada jugador buscando al portero.
		for ( ; ( i_indice_actual < i_num_rivales ); i_indice_actual++ )
		{
			// Si es portero...
			if ( det_rivales[i_indice_actual].esPortero() )
				// ...retornamos el �ndice del jugador "actual".
				return i_indice_actual;
		}

		// No se encuentra al portero, se devuelve un �ndice fuera de rango.
		return -1;
	}
	
	// Predice la posici�n del bal�n en la pr�xima iteraci�n.
	static public Posicion PredicePosBalon(
			Posicion a_pos_balon_it_anterior, Posicion a_pos_balon_actual, double ad_altura )
	{
		// Velocidad en el eje X.
		double d_vel_X = ( a_pos_balon_actual.getX( ) - a_pos_balon_it_anterior.getX( ) );
		
		// Velocidad en el eje Y.
		double d_vel_Y = ( a_pos_balon_actual.getY( ) - a_pos_balon_it_anterior.getY( ) );
		
		if ( ad_altura > 0 )
		{
			// El bal�n va por alto.
			d_vel_X *= Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
			d_vel_Y *= Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
		}
		else
		{
			// El bal�n avanza por el suelo.
			d_vel_X *= Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
			d_vel_Y *= Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
		}

		// Retornamos la posici�n "predecida".
		return new Posicion( ( a_pos_balon_actual.getX( ) + d_vel_X ),
				( a_pos_balon_actual.getY( ) + d_vel_Y ) );
	}
	
	// Determina si vamos a realizar un saque de puerta.
	static public boolean EsSaqueDePuerta( SituacionPartido a_sit_part )
	{
		// Si no estamos sacando, seguro que no es un saque de puerta.
		if ( !a_sit_part.saco() )
			return false;
		
		// Obtenemos la posici�n del bal�n.
		Posicion pos_balon = a_sit_part.balon();

		// Obtenemos la coordenada Y del bal�n.
		double d_pos_y = pos_balon.getY( );
		
		if ( d_pos_y > ( ( - ( Constantes.LARGO_CAMPO_JUEGO / 2 ) ) + Constantes.ANCHO_AREA_GRANDE ) )
			return false;
		
		// Obtenemos la coordenada X del bal�n.
		double d_pos_x = pos_balon.getX( );
		
		if ( Math.abs(d_pos_x) > ( Constantes.LARGO_AREA_GRANDE / 2 ) )
			return false;

		return true;
	}
	
	// Retorna el �ngulo vertical con el que se realizar� el disparo.
	static public double DeterminaAnguloVerticalDisparo(
			double ad_angulo, SituacionPartido a_sit_part )
	{
		// Obtenemos la posici�n actual del bal�n.
		Posicion pos_balon = a_sit_part.balon();
		
		// Obtenemos la posici�n de los jugadores.
		Posicion pos_jugs[] = a_sit_part.misJugadores();
		
		// Obtenemos los detalles de cada jugador.
		JugadorDetalle[] det_jugs = a_sit_part.detalleMisJugadores();
		
		// Obtenemos al jugador propio m�s cercano al bal�n.
		int i_jug_mas_cercano = pos_balon.indiceMasCercano(pos_jugs);
		
		// Obtenemos la velocidad de disparo del jugador m�s cercano al bal�n.
		double d_vel_disp =
			Constantes.REMATE_VELOCIDAD_MIN + ( det_jugs[i_jug_mas_cercano].getRemate() * ConstantesMoyatzoBraves.DIF_VELS_REMATE );

		// S�lo nos importa lo que la pelota avance en el eje Y.
		double /* d_delta_x = Math.cos(ad_angulo) * d_vel_disp, */
        	d_delta_y = Math.sin(ad_angulo);
		
		// Valor del �ngulo inicial.
		double d_ang_vertical = 45.0;
			
		// Variable que guarda la altura del bal�n retornada en la simulaci�n.
		double d_altura_balon;
		
		// Vamos probando �ngulos, empezando desde el que consigue una mayor altura
		//  (45�) hasta el �ngulo 0� (disparo raso). El primero que consiga la altura
		//  ideal (una constante definida), ser� el �ptimo.
		while ( d_ang_vertical > 0.0 )
		{
			// Simula el disparo con los datos dados.
			d_altura_balon = SimularDisparo( d_ang_vertical, d_vel_disp, d_delta_y, pos_balon.getY() );
			
			// �Lo podemos dar por bueno?
			if ( d_altura_balon <= ConstantesMoyatzoBraves.MAX_ALTURA_DISPARO_EN_ARCO )
				return d_ang_vertical;
			
			// Decremento del �ngulo vertical.
			d_ang_vertical -= 0.75;
		}

		return 0.0;
	}

	// Realiza la simulaci�n de un disparo a puerta.
	static private double SimularDisparo(
			double ad_ang_vertical, double ad_vel_disp, double ad_delta_eje_Y, double ad_pos_ini_Y )
	{
		// Pre-condici�n.
		if ( ( ad_delta_eje_Y <= 0 ) || ( ad_vel_disp <= 0 ) || ( ad_ang_vertical > 45 ) ||
				( ad_ang_vertical < 0 ) || ( ad_pos_ini_Y > ConstantesMoyatzoBraves.LINEA_DE_FONDO ) )
			// Devolvemos una altura err�nea.
			return ConstantesMoyatzoBraves.ALTURA_DISPARO_CON_ERROR;
		
		// Convierte el �ngulo vertical a radianes.
		double d_ang_vert_rad =
			( ad_ang_vertical * ConstantesMoyatzoBraves.CONVERT_TO_RADIANS );
		
		// Velocidad del disparo (parte com�n).
		double d_vel =
			ad_vel_disp * Math.cos(d_ang_vert_rad);
		
		// Calcula el desplazamiento inicial en el eje "Z".
		double d_desp_Z = redondeaMultiplo(d_vel * Math.sin(d_ang_vert_rad), Constantes.G);
		
		// Calcula el desplazamiento inicial en el eje "Y" (el "X" no importa).
		double d_desp_Y = ( ad_delta_eje_Y * d_vel );
        
		// Posici�n inicial del bal�n (ejes "Y" y "Z").
		double d_pos_Y = ad_pos_ini_Y, d_pos_Z = 0.0;
		
		// Mientras la pelota no traspase la l�nea de fondo (y lo har� entre
		//  los palos, claro)...
		while ( d_pos_Y <= ConstantesMoyatzoBraves.LINEA_DE_FONDO )
		{
			// Calcula la nueva altura.
			d_pos_Z = redondeaMultiplo(( d_pos_Z + d_desp_Z ), Constantes.G);
			
			// Calcula la nueva posici�n en el eje "Y".
			d_pos_Y += d_desp_Y;
            
			// Frenado del bal�n y ley de la gravedad.
            d_desp_Y *= Constantes.FACTOR_DISMINUCION_VEL_BALON_AIRE;
            d_desp_Z = redondeaMultiplo(( d_desp_Z - Constantes.G ), Constantes.G);
            
            // �El bal�n rebota en el suelo?
            if ( d_pos_Z == 0 )
            {
            	d_desp_Z = (-d_desp_Z - Constantes.G) * Constantes.FACTOR_DISMINUCION_ALTURA_BALON_REBOTE;
            	d_desp_Z = redondeaMultiplo(d_desp_Z, Constantes.G);
            }
            
            // Por seguridad...
            if ( d_desp_Y <= 0 )
            	return ConstantesMoyatzoBraves.ALTURA_DISPARO_CON_ERROR;
		}
		
		// Devuelve la altura al traspasar la l�nea de fondo.
		return d_pos_Z;
	}

	// M�todo copiado del framework. Es c�digo libre. :)
	static private double redondeaMultiplo(double valor, double divisor)
	{
		return Math.round(valor / divisor) * divisor;
    }

}
